import { severityRankings } from 'constants/vulnerabilities';
import { isVulnerabilitySeverity } from 'types/cve.proto';
import type { Exploit, VulnerabilitySeverity } from 'types/cve.proto';
import type { NonEmptyArray } from 'utils/type.utils';
import { getDate } from 'utils/dateUtils';

/**
 * Get the highest severity of any vulnerability in the component array.
 */
export function getHighestVulnerabilitySeverity(
    vulnerabilities: { severity: string }[]
): VulnerabilitySeverity {
    let topSeverity: VulnerabilitySeverity = 'UNKNOWN_VULNERABILITY_SEVERITY';
    vulnerabilities.forEach(({ severity }) => {
        if (
            isVulnerabilitySeverity(severity) &&
            severityRankings[severity] > severityRankings[topSeverity]
        ) {
            topSeverity = severity;
        }
    });
    return topSeverity;
}

/**
 * Get whether or not any component has any fixable vulnerabilities.
 */
export function getIsSomeVulnerabilityFixable(
    vulnerabilities: { fixedByVersion: string }[]
): boolean {
    return vulnerabilities.some(({ fixedByVersion }) => fixedByVersion !== '');
}

/**
 * Gets the highest CVSS score and its score version from all vulnerabilities in the component array.
 */
export function getHighestCvssScore(vulnerabilities: { cvss: number; scoreVersion: string }[]): {
    cvss: number;
    scoreVersion: string;
} {
    let topCvss = 0;
    let topScoreVersion = 'N/A';
    vulnerabilities.forEach(({ cvss, scoreVersion }) => {
        if (cvss > topCvss) {
            topCvss = cvss;
            topScoreVersion = scoreVersion;
        }
    });
    return { cvss: topCvss, scoreVersion: topScoreVersion };
}

export function getHighestNvdCvssScore(
    vulnerabilities: { nvdCvss: number; nvdScoreVersion: string }[]
): {
    nvdCvss: number;
    nvdScoreVersion: string;
} {
    let topCvss = 0;
    let topScoreVersion = 'UNKNOWN_VERSION'; // so CvssFormatted renders as Not available
    vulnerabilities.forEach(({ nvdCvss = 0, nvdScoreVersion = 'UNKNOWN_VERSION' }) => {
        if (nvdScoreVersion !== 'UNKNOWN_VERSION' && nvdCvss > topCvss) {
            topCvss = nvdCvss;
            topScoreVersion = nvdScoreVersion;
        }
    });
    return { nvdCvss: topCvss, nvdScoreVersion: topScoreVersion };
}

export function getEarliestDiscoveredAtTime(
    vulnerabilities: NonEmptyArray<{ discoveredAtImage: string }>
): string {
    let earliestDiscoveredAt = vulnerabilities[0].discoveredAtImage;
    vulnerabilities.forEach(({ discoveredAtImage }) => {
        if (discoveredAtImage < earliestDiscoveredAt) {
            earliestDiscoveredAt = discoveredAtImage;
        }
    });
    return earliestDiscoveredAt;
}

export function hasKnownExploit(exploit: Exploit | null | undefined): exploit is Exploit {
    return Boolean(exploit);
}

export function hasKnownRansomwareCampaignUse(exploit: Exploit | null | undefined) {
    return Boolean(exploit?.knownRansomwareCampaignUse);
}

/**
 * Formats CVE discovered time filter values into user-friendly text
 * @param value - Filter value like ">2024-01-01" or "2024-01-01"
 * @returns Formatted string like "After January 1, 2024"
 */
export function formatCveDiscoveredTime(value: string): string {
    try {
        // Parse the condition prefix and date
        const match = value.match(/^([<>]?)(.+)$/);
        if (!match) {
            return value; // Return original if parsing fails
        }

        const [, condition, dateStr] = match;
        const date = new Date(dateStr);

        // Check if date is valid
        if (Number.isNaN(date.getTime())) {
            return value; // Return original if date is invalid
        }

        const formattedDate = getDate(date);

        // Map conditions to user-friendly text
        switch (condition) {
            case '>':
                return `After ${formattedDate}`;
            case '<':
                return `Before ${formattedDate}`;
            default:
                return `On ${formattedDate}`;
        }
    } catch {
        // Return original value if any error occurs
        return value;
    }
}
